package org.hertsig.collection;

import java.util.Map;
import java.util.Map.Entry;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;

import org.hertsig.entities.Card;
import org.hertsig.entities.CardType;
import org.hertsig.mci.MagicCardsInfo;

import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.Iterables;
import com.google.common.collect.ListMultimap;

@NoArgsConstructor(access=AccessLevel.PRIVATE)
public class CollectionUtils {
	public static <T> ListMultimap<T, Card> group(Map<T, Predicate<Card>> groupings, Iterable<Card> cards) {
		ListMultimap<T, Card> result = ArrayListMultimap.create();
		for (Card card : cards) {
			for (Entry<T, Predicate<Card>> entry : groupings.entrySet()) {
				if (entry.getValue().apply(card)) {
					result.put(entry.getKey(), card);
					break;
				}
			}
			throw new IllegalArgumentException("None of the predicates matches " + card);
		}
		Preconditions.checkState(Iterables.size(cards) == result.size());
		return result;
	}
	
	public static ListMultimap<CardType, Card> deckGrouping(Iterable<Card> cards) {
		return group(ImmutableMap.<CardType, Predicate<Card>>builder()
				.put(CardType.Land, 		(card) -> card.getType().getCardTypes().contains(CardType.Land))
				.put(CardType.Creature, 	(card) -> card.getType().getCardTypes().contains(CardType.Creature))
				.put(CardType.Instant, 		(card) -> card.getType().getCardTypes().contains(CardType.Instant))
				.put(CardType.Sorcery, 		(card) -> card.getType().getCardTypes().contains(CardType.Sorcery))
				.put(CardType.Artifact, 	(card) -> card.getType().getCardTypes().contains(CardType.Artifact))
				.put(CardType.Enchantment, 	(card) -> card.getType().getCardTypes().contains(CardType.Enchantment))
				.put(CardType.Planeswalker, (card) -> card.getType().getCardTypes().contains(CardType.Planeswalker))
				.put(CardType.Plane, 		(card) -> card.getType().getCardTypes().contains(CardType.Plane))
				.put(CardType.Phenomenon, 	(card) -> card.getType().getCardTypes().contains(CardType.Phenomenon))
				.build(), cards);
	}
	
	public enum InventoryGrouping {
		WHITE, BLUE, BLACK, RED, GREEN, COLORLESS, MULTICOLOR, LAND;
	}
	public static ListMultimap<InventoryGrouping, Card> inventoryGrouping(Iterable<Card> cards) {
		return group(ImmutableMap.<InventoryGrouping, Predicate<Card>>builder()
				.put(InventoryGrouping.LAND, 		(card) -> card.getType().getCardTypes().contains(CardType.Land))
				.put(InventoryGrouping.MULTICOLOR, 	(card) -> card.getCost().getColors() > 1)
				.put(InventoryGrouping.WHITE, 		(card) -> card.getCost().isWhite())
				.put(InventoryGrouping.BLUE, 		(card) -> card.getCost().isBlue())
				.put(InventoryGrouping.BLACK, 		(card) -> card.getCost().isBlack())
				.put(InventoryGrouping.RED, 		(card) -> card.getCost().isRed())
				.put(InventoryGrouping.GREEN, 		(card) -> card.getCost().isGreen())
				.put(InventoryGrouping.COLORLESS, 	(card) -> card.getCost().isColorless())
				.build(), cards);
	}
	
	public static ListMultimap<String, Card> setCodeGrouping(Iterable<Card> cards) {
		Builder<String, Predicate<Card>> predicates = ImmutableMap.builder();
		for (String setCode : MagicCardsInfo.getSets().keySet()) {
			predicates.put(setCode, (card) -> card.getSetCode().equals(setCode));
		}
		return group(predicates.build(), cards);
	}
}
